#include "NetcdfWrapper.h"
#include "NetcdfDimensionWrapper.h"
#include "OCVolume/GridBinReader.h"

namespace OCPP {
	NetcdfWrapper::~NetcdfWrapper()
	{
		close();
	}

	bool NetcdfWrapper::open(String fileName)
	{
		String ext = FileUtil::getFileExtension(fileName);
		StringUtil::toLowerCase(ext);
		if (ext == "nc")
		{
			ncWrapper = std::make_shared<NetcdfNcReader>();
		}
		else if(ext == "bin")
		{
			ncWrapper = std::make_shared<GridBinReader>();
		}
		else
		{
			ncWrapper = std::make_shared<NetcdfGribReader>();
		}
		return ncWrapper->open(fileName);
	}

	void NetcdfWrapper::close()
	{
		if (ncWrapper != nullptr) {
			ncWrapper->close();
		}
		ncWrapper = nullptr;
	}

	Volume::GridDataVec NetcdfWrapper::read(String var, const Volume::VolumeOptions& options, int desiredLevel)
	{
		GridDataVec vec;
		GridVariablePtr variable = ncWrapper->findVariable(var);
		if (variable == nullptr)
		{
			OCPP_LOG_ERROR << "no variable " << var << "\n";
			return vec;
		}
		variable->_gridFileReaderPtr = ncWrapper;

		NetcdfDimensionWrapper netcdfDimensionWrapper;
		netcdfDimensionWrapper.read(variable, options);


		auto dimY = netcdfDimensionWrapper.dimX;
		auto dimX = netcdfDimensionWrapper.dimY;

		if (dimY == nullptr || dimX == nullptr) {
			OCPP_LOG_ERROR << "no dimension lon lat\n";
			return vec;
		}

		bool extract2D = desiredLevel > -1;

		auto dimT = netcdfDimensionWrapper.dimT;
		auto dimZ = netcdfDimensionWrapper.dimZ;
		if (dimT != nullptr && dimZ != nullptr) {
			for (int t = 0; t < dimT->size; t++) {
				if (extract2D)
				{
					GridData gridData = netcdfDimensionWrapper.getShapeDataByTZ(t, desiredLevel, variable, options);
					vec.push_back(std::move(gridData));
				}
				else
				{
					GridData gridData = netcdfDimensionWrapper.getShapeDataByT(t, variable, options);
					vec.push_back(std::move(gridData));
				}
			}
		}
		else if (dimT != nullptr) {
			for (int t = 0; t < dimT->size; t++) {
				GridData gridData = netcdfDimensionWrapper.getShapeDataByT(t, variable, options);
				vec.push_back(std::move(gridData));
			}
		}
		else if (dimZ != nullptr) {
			if (extract2D)
			{
				GridData gridData = netcdfDimensionWrapper.getShapeDataByZ(desiredLevel, variable, options);
				vec.push_back(std::move(gridData));
			}
			else
			{
				GridData gridData = netcdfDimensionWrapper.getShapeData(variable, options);
				vec.push_back(std::move(gridData));
			}
		}

		return vec;
	}

	void NetcdfWrapper::extract(String var, const Volume::VolumeOptions& options,int desiredLevel)
	{
		GridDataVec vec = read(var, options, desiredLevel);
		for (auto& gridData : vec)
		{
			options.getWriter().write(gridData, options);
		}
	}
}